home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / general / viewers / polyview / polyvw31.lha / Polyview3.1 / new / pvvset.c < prev    next >
C/C++ Source or Header  |  1993-08-13  |  32KB  |  1,074 lines

  1. /*****************************************************************************
  2.  * NCSA Polyview 3.1                                                         *
  3.  *                                                                           *
  4.  * Version 3.1 changes and additions by Gilles Bourhis                       *
  5.  * Version 3 changes and additions by Marc Andreessen.                       *
  6.  * Version 2 by Brian Calvert.                                               *
  7.  *                                                                           *
  8.  * Software Development Group                                                *
  9.  * National Center for Supercomputing Applications                           *
  10.  * University of Illinois at Urbana-Champaign                                *
  11.  *                                                                           *
  12.  * This is BETA release software.  As such it may contain software bugs and  *
  13.  * exhibit inconsistencies.                                                  *
  14.  *                                                                           *
  15.  * Please send bug reports to polyview@ncsa.uiuc.edu.                        *
  16.  *                                                                           *
  17.  * Copyright (c) 1992 The Board of Trustees of the University of Illinois.   *
  18.  *                                                                           *
  19.  * Permission to use, copy, and modify this software and its                 *
  20.  * documentation for educational, research, and non-profit purposes is       *
  21.  * hereby granted, provided that the above copyright notice, the original    *
  22.  * authors names, and this permission notice appear in all such copies.      *
  23.  * Any distribution of this software requires the explicit and written       *
  24.  * authorization of the authors.                                             *
  25.  *                                                                           *
  26.  * The University of Illinois makes no representations about the             *
  27.  * suitability of this software for any purpose.  It is provided "as is"     *
  28.  * without warranty of any kind.                                             *
  29.  *****************************************************************************/
  30.  
  31. /* $Id: pvvset.c,v 1.4 93/08/13 12:51:16 gbourhis Exp $ */
  32.  
  33. #ifdef RCSLOG
  34. $Log:    pvvset.c,v $
  35.  * Revision 1.4  93/08/13  12:51:16  gbourhis
  36.  * changes in set_file_dtm_explicit().
  37.  * 
  38.  * Revision 1.3  93/07/13  16:47:25  gbourhis
  39.  * use file handle field, better testing of data type in swap_in().
  40.  * 
  41.  * Revision 1.2  93/06/25  09:02:46  gbourhis
  42.  * Modifs needed to use HDF 3.2
  43.  * 
  44.  * Revision 1.1  92/09/18  10:55:26  marca
  45.  * Initial revision
  46.  * 
  47. #endif
  48.  
  49. #include "pv.h"
  50.  
  51. static Vgroup_t *create_vgroup(state_t *state, int id, char *name)
  52. {
  53.   Vgroup_t        *new;
  54.   
  55.   new = (Vgroup_t *) PVMALLOC(sizeof(Vgroup_t));
  56.   strcpy(new->name, name);
  57.   new->id = id;
  58.   new->children_read = FALSE;
  59.   new->sibling = NULL;
  60.   new->groups = NULL;
  61.   new->vdatas = NULL;
  62.   
  63.   return new;
  64. }
  65.  
  66.  
  67. static files_t *create_file(state_t *state, int type, char *path)
  68. {
  69.   files_t            *new;
  70.   
  71.   new = (files_t *) PVMALLOC(sizeof(files_t));
  72.   new->type = type;
  73.   strcpy(new->path, path);
  74.   
  75.   /* Create dummy root group. */
  76.   new->groups = create_vgroup(state, -1, "/");
  77.   new->groups->file = new;
  78.   new->portid = DTMERROR;
  79.   new->vdatas = NULL;
  80.   new->next = NULL;
  81.   
  82.   return new;
  83. }
  84.  
  85.  
  86. /* external */
  87. Vdata_t *create_vdata(state_t *state, int id, char *name, files_t *source)
  88. {
  89.   Vdata_t *new;
  90.   int i;
  91.   
  92.   new = (Vdata_t *) PVMALLOC(sizeof(Vdata_t));
  93.   strcpy(new->name, name);
  94.   new->id = id;
  95.   new->file = source;
  96.   new->locked = FALSE;
  97.   new->in_memory = FALSE;
  98.   new->last_used = 0;
  99.   new->stats_read = FALSE;
  100.   
  101.   new->sibling = NULL;
  102.   new->next = NULL;
  103.  
  104.   for (i = 0; i < MAXDATADIMS; i++)
  105.     new->stats[i].rec_count = new->stats[i].rec_size = 0;
  106.   
  107.   return new;
  108. }
  109.  
  110.  
  111. /* add_file creates a new in-memory file record and inserts it into the */
  112. /* vset structure.  Returns a pointer to the new file record. */
  113. static files_t *add_file(state_t *state, int type, char *path)
  114. {
  115.   files_t *new;
  116.   
  117.   /* Create a new record for the file. */
  118.   new = create_file(state, type, path);
  119.   
  120.   /* Link the file into the vset pool. */
  121.   new->next = state->files;
  122.   state->files = new;
  123.   
  124.   return new;
  125. }
  126.  
  127.  
  128.  
  129. files_t *set_file_dtm_explicit (state_t *state, char *path)
  130. {
  131.   files_t    *file;
  132.  
  133.   for (file = STA_SOURCES(state); file != NULL; file = file->next)
  134.     if (file->type == DTMPORT && strcmp(file->path, path)==0)
  135.       break;
  136.  
  137.   return (file == NULL) ? add_file (state, DTMPORT, path) : file;
  138. }
  139.  
  140.  
  141.  
  142. static files_t *set_file(state_t *state, int type, char *path)
  143. {
  144.   int        vgid;
  145.   VGROUP    *vghandle;
  146.   char        name[MAXNAMELEN];
  147.   files_t    *file;
  148.   FILE        *fp;
  149.     
  150.   /* Find the file's record in the vset pool. */
  151.   for (file = STA_SOURCES(state); file != NULL; file = file->next) 
  152.     if (strcmp(file->path, path) == 0) 
  153.       break;
  154.   
  155.   /* Does the file exist in the vset pool? */
  156.   if (file == NULL) 
  157.     {
  158.       /* File does not exist in the pool.  Make sure that it exists */
  159.       /* on the disk before adding it to the vset pool. */
  160.       if (type != DTMPORT) 
  161.         {
  162.           if ((fp = fopen(path, "r")) == NULL) {
  163.             /* The file either doesn't exist or is unreadable. */
  164.             /* Quit without making a change to the active file. */
  165.             stprintf (state, "ERROR:  '%s' cannot be opened.\n", path);
  166.             return NULL;
  167.           }
  168.           fclose(fp);
  169.         }
  170.       
  171.       file = add_file(state, type, path);
  172.       
  173.       /* Initialize the state for the new file. */
  174.       switch (file->type) 
  175.         {
  176.           /* What's the point of handling these? */
  177.         case HDFRIS8:
  178.         case HDFSDS:
  179.           if ((file->fh =  Hopen(path, DFACC_READ, 0)) < 0)
  180.             return NULL;
  181.           break;
  182.           
  183.         case HDFVSET:
  184.           if ((file->fh =  Vopen(path, DFACC_READ, 0)) < 0)
  185.             return NULL;
  186.           
  187.           /* If the root group id is not there, get it. */
  188.           if ((type == HDFVSET) && (file->groups->id == -1)) 
  189.             {
  190.               vgid = -1;
  191.               while ((vgid = Vgetid(file->fh, vgid)) != -1) 
  192.                 {
  193.                   vghandle = Vattach(file->fh, vgid, "r");
  194.                   Vgetname(vghandle, name);
  195.                   Vdetach(vghandle);
  196.                   if ((name[0] == '/') && (name[1] == '\0')) 
  197.                     {
  198.                       /* Found root vgroup. */
  199.                       file->groups->id = vgid;
  200.                       break;
  201.                     }
  202.                 }
  203.               
  204.               if (vgid == -1) 
  205.                 {
  206.                   stprintf 
  207.                     (state, 
  208.                      "File does not contain '/' group; assuming all groups contained by root.");
  209.                 }
  210.             }
  211.           
  212.           break;
  213.           
  214.         case UNIX:
  215.           fprintf(stderr, "ERROR:  File type unsupported.\n");
  216.           fflush (stderr);
  217.           break;
  218.           
  219.         case DTMPORT:
  220.           /* MARC: Added extra (dummy) parameter '0' to DTMmakeInPort;
  221.              DTM 2.0 source claims this is reserved for future use. */
  222.           COMdtm_in (state, path);
  223.           break;
  224.         default:
  225.           fprintf(stderr, "[set_file] SYSTEM ERROR:  File type undefined.\n");
  226.           fflush (stderr);
  227.           break;
  228.         }
  229.     }
  230.   
  231.   return file;
  232. }
  233.  
  234.  
  235.  
  236. /* path parse splits a pathname into its filepath, vgroup path, and vdata */
  237. /* name components, according to the pathtype passed to it.  If any of the */
  238. /* pieces are not found, the arrays passed to the function are not modified. */
  239. /* Returns ST_OKAY if no errors occur. */
  240.  
  241. /* Breaks a fullpath name into file, vgroup, and vdata components according */
  242. /* to its pathtype.   Legal FILEPATH is composed of any characters except */
  243. /* for a colon.  A VGROUPPATH is of the form "[<filepath>:]<vgrouppath>". */
  244. /* A VDATANAME is of the form "[<filepath>:][[vgrouppath>/]<vdataname>". */
  245. /* Returns ST_OKAY if no errors occur. */
  246. static int parse_path(state_t *state, char *fullpath, int pathtype, 
  247.                       char *filepath, char *vgrouppath, char *vdataname)
  248. {
  249.   char *vg;
  250.   char *vd;
  251.   
  252.   /* If there is a colon separator it denotes the break between the */
  253.   /* file pathname and the vgroup path.  The last slash in the string */
  254.   /* may mark where the vdata name occurs.  Set the colon to an null */
  255.   /* character and set vgp to point to the following substring. */
  256.   vg = strchr(fullpath, ':');
  257.   vd = strrchr(fullpath, '/');
  258.   if (vg != NULL) 
  259.     {
  260.       *vg = '\0';
  261.       vg++;
  262.     }
  263.   
  264.   /* If there is a last slash and the pathtype is a VDATANAME and the */
  265.   /* slash occurs after whatever vgroupname there is starts, then */
  266.   /* it is useful to break the vdataname off of the rest of the */
  267.   /* string. */
  268.   if ((vd != NULL) && (pathtype == VDATANAME) && (vd >= vg)) 
  269.     {
  270.       *vd = '\0';
  271.       vd++;
  272.     }
  273.   else 
  274.     {
  275.       vd = NULL;
  276.     }
  277.   
  278.   switch (pathtype) 
  279.     {
  280.     case FILEPATH:
  281.       if (vg != NULL) 
  282.         {
  283.           /* Colons are not allowed in file pathnames as they delimit */
  284.           /* group names. */
  285.           printf("ERROR:  Colon in file path '%s:%s'\n", fullpath, vg);
  286.           return ST_ERROR;
  287.         }
  288.       strcpy(filepath, fullpath);
  289.       break;
  290.     case VGROUPPATH:
  291.       if (vg == NULL) 
  292.         /* No file pathname, just group name. */
  293.         strcpy(vgrouppath, fullpath);
  294.       else 
  295.         {
  296.           /* File pathname and groupname. */
  297.           strcpy(filepath, fullpath);
  298.           strcpy(vgrouppath, vg);
  299.         }
  300.       break;
  301.     case VDATANAME:
  302.       if (vg == NULL) 
  303.         {
  304.           if (vd == NULL) 
  305.             /* Just a VDATANAME, nothing else. */
  306.             vd = fullpath;
  307.           else 
  308.             /* VDATANAME and a VGROUPPATH */
  309.             vg = fullpath;
  310.         }
  311.       else {
  312.         /* A filepath is included in this path */
  313.         strcpy(filepath, fullpath);
  314.         if (vd == NULL) 
  315.           {
  316.             /* Just a VDATANAME after the filepath */
  317.             vd = vg;
  318.             vg = NULL;
  319.           }
  320.       }
  321.       
  322.       /* Get the vdata name and group path name. */
  323.       strcpy(vdataname, vd);
  324.       if (vg != NULL)
  325.         strcpy(vgrouppath, vg);
  326.       
  327.       break;
  328.     default:
  329.       fprintf(stderr, "[parse_path] SYSTEM ERROR:  %d not valid pathtype.\n",
  330.               pathtype);
  331.       fflush (stderr);
  332.       break;
  333.     }
  334.   
  335.   return ST_OKAY;
  336. }
  337.  
  338.  
  339. static int GetNextId(int32 f, VGROUP *vgptr, int id)
  340. {
  341.   if (vgptr == NULL)
  342.     return Vgetid(f, id);
  343.   else
  344.     return Vgetnext(vgptr, id);
  345. }
  346.  
  347.  
  348. static int IsVgroup(VGROUP *vgptr, int id)
  349. {
  350.   return (vgptr == NULL) ? TRUE : Visvg(vgptr, id);
  351. }
  352.  
  353.  
  354. static int IsVdata(VGROUP *vgptr, int id)
  355. {
  356.   return (vgptr == NULL) ? TRUE : Visvs(vgptr, id);
  357. }
  358.  
  359.  
  360.  
  361.  
  362. /* ------------------------------------------------------------------------ */
  363. /* --------------------------- PUBLIC ROUTINES ---------------------------- */
  364. /* ------------------------------------------------------------------------ */
  365.  
  366.  
  367. /* Returns a pointer to the vdata at fullpath.  fullpath is the name of a */
  368. /* vdata, which may include a filename or vgroup path.  Returns NULL if an */
  369. /* error occurs. */
  370. Vdata_t *find_vdata(state_t *state, Vgroup_t *vg, char *vdataname)
  371. {
  372.   Vdata_t *vdata;
  373.  
  374.   assert (vg == NULL);
  375.   
  376.   /* Now that the proper file and vgroup are set in the state, */
  377.   /* search for the vdata. */
  378.   for (vdata = VGR_VDATAS(vg); vdata; vdata = VDA_SIBLING(vdata)) 
  379.     if (strwcmp(vdataname, VDA_NAME(vdata)) == 0) 
  380.       break;
  381.   
  382.   /* If the vgroup was not found, return peacefully. */
  383.   if (vdata == NULL) 
  384.     return NULL;
  385.   
  386.   /* Now that we have a pointer to the vdata, get the data associated */
  387.   /* with the record. */
  388.   return get_vdata(state, vdata);
  389. }
  390.  
  391. /* get vgroup in group returns a pointer to the vgroup under the group with */
  392. /* the proper name.  The function requires the system state, a pointer to */
  393. /* the group to be serarched, and the name of the vgroup to be checked. */
  394. /* Returns the vgroup's pointer, NULL otherwise. */
  395. /* CURRENTLY NOT USED */
  396. Vgroup_t *GetVgroupInVgroup(state_t *state, Vgroup_t *group, char *name)
  397. {
  398.   Vgroup_t *vgroup;
  399.     
  400.   assert (group != NULL);
  401.   
  402.   /* Look for the vgroup under the group with the proper name. */
  403.   /* Wildcarded names are accepted. */
  404.   for (vgroup = VGR_GROUPS(group); vgroup != NULL; 
  405.        vgroup = VGR_SIBLING(vgroup)) 
  406.     {
  407.       if (strwcmp(name, VGR_NAME(vgroup)) == 0)
  408.         return vgroup;
  409.     }
  410.   
  411.   return NULL;
  412. }
  413.  
  414.  
  415. /* set vgroup sets the active vgroup to the one located at the grouppath */
  416. /* passed to the function.  The group is located within the active file. */
  417. /* If the group is found, the pointer to its memory-based copy is returned. */
  418. /* If the group is not found in the file, the function returns NULL. */
  419. Vgroup_t *set_vgroup(state_t *state, files_t *file, char *grouppath)
  420. {
  421.   Vgroup_t *curr;
  422.   char *groupname;
  423.   char tmp[MAXPATHLEN];
  424.     
  425.   /* If there is no active file, running this function is */
  426.   /* senseless. */
  427.   if (file == NULL) {
  428.     printf("[set_vgroup] WARNING:  No active file set.  Group not changed.\n");
  429.     return NULL;
  430.   }
  431.     
  432.   /* If an empty group name is provided, then an error has occurred. */
  433.   if (*grouppath == '\0') {
  434.     printf("[set_vgroup] WARNING:  No group specified.  Group not changed.\n");
  435.     return NULL;
  436.   }
  437.     
  438.   /* Copy the name of the grouppath so that we can modify it using */
  439.   /* strtok(). */
  440.   strcpy(tmp, grouppath);
  441.   groupname = tmp;
  442.     
  443.   /* Ignore any leading slash. */
  444.   if (*groupname == '/') {
  445.     groupname++;
  446.   }
  447.     
  448.   /* Set up the current Vgroup record pointer and the groupname for */
  449.   /* the first group. */
  450.   curr = file->groups;
  451.   groupname = strtok(groupname, "/");
  452.   
  453.   while (groupname != NULL) {
  454.     /* If the group's children haven't been read in yet, do so. */
  455.     build_vgroup_children(state, curr);
  456.     
  457.     /* Search current's group children for a group with the same */
  458.     /* name. */
  459.     for (curr = curr->groups; curr != NULL; curr = curr->sibling) {
  460.       if (strwcmp(groupname, curr->name) == 0) {
  461.         break;
  462.       }
  463.     }
  464.         
  465.     /* If we didn't find a match among the children, then the */
  466.     /* path is bogus. */
  467.     if (curr == NULL) {
  468.       return NULL;
  469.     }
  470.     else {
  471.       groupname = strtok(NULL, "/");
  472.     }
  473.   }
  474.     
  475.   /* Now that the group has been found, make sure that its children */
  476.   /* are read in. */
  477.   build_vgroup_children(state, curr);
  478.   
  479. #if 0
  480.   WIN_GROUP(win) = curr;
  481. #endif
  482.   
  483.   return curr;
  484. }
  485.  
  486.  
  487.  
  488. /* build vgroup children reads into memory the records for the current */
  489. /* vgroup's child vgroup and vdatas, if they haven't been read yet.  The */
  490. /* vgroup's children_read flag provides the cue.  The function takes */
  491. /* pointers to the system state and the current vgroup.  Returns ST_OKAY */
  492. /* if no errors occur. */
  493. int build_vgroup_children(state_t *state, Vgroup_t *current)
  494. {
  495.   VGROUP *vgptr;
  496.   VGROUP *vghandle;
  497.   VDATA *vdhandle;
  498.   int id;
  499.   int curr_id;
  500.   char name[MAXNAMELEN];
  501.   files_t *file;
  502.   
  503.   /* Check that the vgroup is correctly connected to a file record. */
  504.   file = VGR_FILE(current);
  505.   if (file == NULL) {
  506.     printf("ERROR:  Bad file reference in build_vgroup_children\n");
  507.     return ST_ERROR;
  508.   }
  509.   
  510.   if (file->type != DTMPORT)
  511.     {
  512.       /* Make sure that we need to read in the children before we do */
  513.       /* anything. */
  514.       if (current->children_read == FALSE) 
  515.         {
  516.           current->children_read = TRUE;
  517.  
  518.           if (current->id == -1)
  519.             {
  520.               curr_id = Vgetid(file->fh, -1);
  521.               vgptr = NULL;
  522.             }
  523.           else
  524.             {
  525.               curr_id = current->id;
  526.               vgptr =  Vattach(file->fh, curr_id, "r");
  527.             }
  528.           
  529.           id = -1;
  530.           while ((id = GetNextId(file->fh,vgptr,id)) != -1)
  531.             {
  532.               if (IsVgroup(vgptr, id)) 
  533.                 {
  534.                   /* This item is a group. */
  535.                   vghandle =  Vattach(file->fh, id, "r");
  536.                   Vgetname(vghandle, name);
  537.                   Vdetach(vghandle);
  538.                   
  539.                   add_vgroup(state, id, name, current);
  540.                 }
  541.               else if (IsVdata(vgptr, id))
  542.                 {
  543.                   /* This item is a data. */
  544.                   vdhandle =  VSattach(file->fh, id, "r");
  545.                   VSgetname(vdhandle, name); /*vdata name */
  546.                   VSdetach(vdhandle);
  547.                   
  548.                   add_vdata(state, id, name, current);
  549.                   /* LATER... VSinquire(vshandle - vdata and field names */
  550.                 }
  551.               else
  552.                 {
  553.                   printf("[build_vgroup_children] ERROR:\n  %s %s\n", 
  554.                          "Unsupported data type encountered",
  555.                          "in file");
  556.                   return NULL;
  557.                 }
  558.             }
  559.         }
  560.     }
  561.   
  562.   return ST_OKAY;
  563. }
  564.  
  565.  
  566.  
  567. /* Creates a new in-memory vgroup record and inserts it under the "parent" */
  568. /* vgroup provided in the arguments.  If parent is NULL, the new vgroup is */
  569. /* linked as the first child of the active file.  Returns a pointer to the */
  570. /* new vgroup record, NULL if an error occurs. */
  571. Vgroup_t *add_vgroup(state_t *state, int id, char *name, Vgroup_t *parent)
  572. {
  573.   Vgroup_t *new;
  574.   Vgroup_t *curr;
  575.     
  576.   /* Create a new Vgroup_t record and fill its fields with values */
  577.   /* passed to this function. */
  578.   new = create_vgroup(state, id, name);
  579.   
  580.   /* Depending on the value of parent, link the record into a */
  581.   /* structure. */
  582.   /* This doesn't look like the new vgroup is ``linked as the first
  583.      child of the active file'' to me... */
  584.   if (parent == NULL) 
  585.     {
  586.       printf("SYSTEM ERROR:  parent NULL in add_vgroup.\n");
  587.       return NULL;
  588.     }
  589.   else 
  590.     {
  591.       curr = parent->groups;
  592.       if (curr == NULL) {
  593.         /* Link the record as a child of the parent. */
  594.         parent->groups = new;
  595.       }
  596.       else 
  597.         {
  598.           /* Find the last group and link the new record after it. */
  599.           while (curr->sibling != NULL) 
  600.             curr = curr->sibling;
  601.           curr->sibling = new;
  602.         }
  603.       VGR_FILE(new) = VGR_FILE(parent);
  604.     }
  605.   
  606.   return new;
  607. }
  608.  
  609.  
  610. /* Creates a new vdata with the specified name and id and inserts it as a */
  611. /* of the parent.  If parent is NULL, the vdata is made a child of the */
  612. /* active file record.  Returns a pointer to the new vdata record, NULL if */
  613. /* an error occurs. */
  614. Vdata_t *add_vdata(state_t *state, int id, char *name, Vgroup_t *parent)
  615. {
  616.   Vdata_t *new;
  617.     
  618.   /* Without a parent, the vdata cannot be linked in. */
  619.   assert (parent != NULL);
  620.   
  621.   /* Create a new Vdata_t record and fill its fields with values */
  622.   /* passed to this function. */
  623.   new = create_vdata(state, id, name, VGR_FILE(parent));
  624.   
  625.   /* Add the Vdata to the pool associated with this file. */
  626.   new->next = VGR_FILE(parent)->vdatas;
  627.   VGR_FILE(parent)->vdatas = new;
  628.   
  629.   /* Insert the new vdata as the first child of the parent (assume */
  630.   /* that the order of vdatas is unimportant). */
  631.   new->sibling = parent->vdatas;
  632.   parent->vdatas = new;
  633.   
  634.   return new;
  635. }
  636.  
  637.  
  638. /* Gets a pointer to the swapped-in vdata record.  Returns a pointer to the */
  639. /* record, NULL if an error occurs. */
  640. Vdata_t *get_vdata(state_t *state, Vdata_t *vdata)
  641. {
  642.   /* Check that a non-null vdata pointer is provided. */
  643.   /* For some reason this is always happening these days... */
  644.   if (vdata == NULL)
  645.     return NULL;
  646.   
  647.   /* Just call swap_in.  If the vdata is not already in memory, it */
  648.   /* will take care of it. */
  649.   if (swap_in(state, vdata) != ST_OKAY) {
  650.     printf("ERROR:  Undable to swap in %s dataset.\n", vdata->name);
  651.     return NULL;
  652.   }
  653.   
  654.   return vdata;
  655. }
  656.  
  657.  
  658. /* get vdata in group returns a pointer to the vdata under the group with */
  659. /* the proper name.  The function requires the system state, a pointer to */
  660. /* the group to be serarched, and the name of the vdata to be checked. */
  661. /* Returns the vdata's pointer, NULL otherwise. */
  662. Vdata_t *get_vdata_in_vgroup(state_t *state, Vgroup_t *group, char *name)
  663. {
  664.   Vdata_t *vdata;
  665.  
  666.   assert (group != NULL);
  667.   
  668.   /* Look for the vdata under the group with the proper name. */
  669.   /* Wildcarded names are accepted. */
  670.   for (vdata = VGR_VDATAS(group); vdata != NULL; vdata = VDA_SIBLING(vdata)) 
  671.     if (strwcmp(name, VDA_NAME(vdata)) == 0)
  672.       return vdata;
  673.   
  674.   return NULL;
  675. }
  676.  
  677.  
  678.  
  679. /* Returns a pointer to the file record associated with the file at */
  680. /* fullpath.  Returns NULL if an error occurs. */
  681. files_t *find_file (state_t *state, int type, char *fullpath)
  682. {
  683.   char filepath[MAXLINELEN];
  684.   long portid;
  685.   files_t *file;
  686.  
  687.   if (type == DTMPORT) 
  688.     {
  689.       /* Check that there is a colon.  Must be of the form: */
  690.       /*              [host]:portid */
  691.       /* where 1024 < portid <= 65536 */
  692.       if ((sscanf(fullpath, ":%ld", &portid) != 1) &&
  693.           (sscanf(fullpath, "%*[^:]:%ld", &portid) != 1)) 
  694.         {
  695.           bprintf(state, "ERROR:  Colon required in port name.\n");
  696.           return NULL;
  697.         }
  698.       else 
  699.         {
  700.           if ((portid < 1024) || (portid > 65536))
  701.             {
  702.               bprintf(state, "ERROR:  Port ID must be between ");
  703.               bprintf(state, "1024 and 65536.\n");
  704.               return NULL;
  705.             }
  706.           strcpy(filepath, fullpath);
  707.         }
  708.     }
  709.   else 
  710.     {
  711.       /* Check that we have a legal file pathname. */
  712.       if (parse_path(state, fullpath, FILEPATH, filepath,
  713.                      NULL, NULL) == ST_ERROR) 
  714.         {
  715.           bprintf(state, "ERROR:  Illegal file name '%s'.\n", fullpath);
  716.           return NULL;
  717.         }
  718.     }
  719.   
  720.   /* Set the state to that file. */
  721.   if ( (file = set_file(state, type, filepath)) == NULL ) 
  722.     {
  723.       stprintf(state, "ERROR:  Problem reading file %s.\n", filepath);
  724.  
  725.       /* It would seem that we don't need to have a dialog here... */
  726.       return NULL;
  727.     }
  728.   
  729.   /* Return the pointer to the file record that was found. */
  730.   return file;
  731. }
  732.  
  733.  
  734. /* Returns a pointer to the vgroup at fullpath.  fullpath is the name of a */
  735. /* vgroup, which may include a filename.  The difference between this */
  736. /* and get_vdata_in_group is mysterious. */
  737. Vgroup_t *find_vgroup(state_t *state, files_t *file, char *fullpath)
  738. {
  739.   Vgroup_t *vgroup;
  740.   
  741.   if (file == NULL) 
  742.     {
  743.       bprintf(state, "[find_vgroup] ERROR: Must choose a file first.\n");
  744.       return NULL;
  745.     }
  746.   
  747.   /* If a vgroup name was specified, set the state to that vgroup. */
  748.   if ( (vgroup = set_vgroup(state, file, fullpath)) == NULL)
  749.     return NULL;
  750.   
  751.   /* Return a pointer to the vgroup that was chosen. */
  752.   return vgroup;
  753. }
  754.  
  755.  
  756. /* Swaps a vdata's information into memory if it is not already in memory. */
  757. /* Updates the "last_used" time accordingly.  Recalculates the data set's */
  758. /* statistics, if necessary.  Returns ST_OKAY if no errors occur. */
  759. int swap_in(state_t *state, Vdata_t *vdata)
  760. {
  761.   VDATA    *vdhandle;
  762.   char name[MAXNAMELEN];
  763.   char fields[MAXNAMELEN];
  764.   int32 nv, interlace, vsize, forder, ftype, nfields;
  765.   int16 *buff;
  766.   int i;
  767.   
  768.   /* If this a bad vdata pointer, quit the function. */
  769.   assert (vdata != NULL);
  770.   
  771.   /* Is the data already in memory? */
  772.   if (vdata->in_memory == TRUE) 
  773.     {
  774.       /* All we need to do is update the last used time. */
  775.       /* WHAT FOR?  This isn't used anywhere else in the code. */
  776.       vdata->last_used = state->redraw_count;
  777.     }
  778.   else 
  779.     {
  780.       /* The data has not been read in yet.  Read it in. */
  781.       
  782.       /* Hook up to the data. */
  783.       vdhandle = VSattach (vdata->file->fh, vdata->id, "r");
  784.       VSinquire (vdhandle, &nv, &interlace, fields, &vsize, name);
  785.       VSsetfields(vdhandle, fields);
  786.       nfields = VFnfields(vdhandle);
  787.       ftype = VFfieldtype(vdhandle, 0);
  788.       for (i=0, forder = 0; i< nfields; i++)
  789.     forder += VFfieldorder(vdhandle, i);
  790. #if 0
  791.       stprintf
  792.         (state, "Reading %s:%s ...\n", vdata->file->path, VDA_NAME(vdata));
  793. #endif
  794.       if (ftype == DFNT_INT16 && sizeof(int16) < sizeof(int)) {
  795.     buff = (int16 *)malloc(nv * vsize);
  796.     if (buff == NULL)
  797.       {
  798.         fprintf(stderr, "[swap_in] ERROR:  Cannot perform malloc.\n");
  799.         fflush (stderr);
  800.         return ST_ERROR;
  801.       }
  802.     if (VSread(vdhandle, (unsigned char *)buff, nv, interlace) == -1)
  803.       {
  804.         fprintf(stderr, "[swap_in] ERROR:  Problem during read.\n");
  805.         fflush (stderr);
  806.         return ST_ERROR;
  807.       }
  808.     vsize *= 2;
  809.     vdata->data = (char *) PVMALLOC(nv * vsize * sizeof (char));
  810.     if (vdata->data == NULL)
  811.       {
  812.         fprintf(stderr, "[swap_in] ERROR:  Cannot perform malloc.\n");
  813.         fflush (stderr);
  814.         return ST_ERROR;
  815.       }
  816.     for (i = 0; i < nv*forder; i++)
  817.       *((int *)vdata->data+i) = buff[i];
  818.     free(buff);
  819.       }
  820.       else {
  821.     vdata->data = (char *) PVMALLOC(nv * vsize * sizeof (char));
  822.     if (vdata->data == NULL)
  823.       {
  824.         fprintf(stderr, "[swap_in] ERROR:  Cannot perform malloc.\n");
  825.         fflush (stderr);
  826.         return ST_ERROR;
  827.       }
  828.     if (VSread(vdhandle, (unsigned char *)vdata->data, nv, interlace) ==
  829.         -1) 
  830.       {
  831.         fprintf(stderr, "[swap_in] ERROR:  Problem during read.\n");
  832.         fflush (stderr);
  833.         return ST_ERROR;
  834.       }
  835.       }
  836.       
  837.       VSdetach(vdhandle);
  838.       
  839.       vdata->in_memory = TRUE;
  840.       /* What is rec_count/rec_size/rec_type doing
  841.          in stats[0]???  This is a silly hack. */
  842.       vdata->stats[0].rec_count = nv;
  843.       vdata->stats[0].rec_size = vsize / sizeof(int);
  844.  
  845.       /* KLUDGE! -- This does not check for other data types. */
  846.       /* If the record is larger than one element, then assume */
  847.       /* that it is PVINTEGER, otherwise, assume PVFLOAT. */
  848.       /* BOY, this is stupid. */
  849.       if (vsize > sizeof(int) && ftype != DFNT_FLOAT32)
  850.         vdata->stats[0].type = PVINTEGER;
  851.       else
  852.         vdata->stats[0].type = PVFLOAT;
  853.       
  854.       if (!(vdata->stats_read))
  855.         calc_stats(state, vdata);
  856.     }
  857.   
  858.   return ST_OKAY;
  859. }
  860.  
  861.  
  862. /* Calculates the min, mean, max, and variance of a given vdata, storing the */
  863. /* statistics in the record.  Returns ST_OKAY. */
  864. int calc_stats(state_t *state, Vdata_t *vdata)
  865. {
  866.   int        i, j, n, m;
  867.   int        *iptr;
  868.   register int    ival;
  869.   long        imin[MAXDATADIMS], imax[MAXDATADIMS];
  870.   long        imean[MAXDATADIMS], imeansq[MAXDATADIMS];
  871.   float        *fptr;
  872.   register float    fval;
  873.   double    fmin[MAXDATADIMS], fmax[MAXDATADIMS];
  874.   double    fmean[MAXDATADIMS], fmeansq[MAXDATADIMS];
  875.  
  876.   m = vdata->stats[0].rec_size;
  877.   n = vdata->stats[0].rec_count;
  878.  
  879.   PVD (("+++ [calc_stats] vdata is %s\n", vdata->name));
  880.   PVD (("[calc_stast] rec_size is %d, rec_count is %d\n", m, n));
  881.   
  882.   switch (vdata->stats[0].type) 
  883.     {
  884.     case PVINTEGER:
  885.       PVD (("  [cs] Processing PVINTEGER.\n"));
  886.       for (j = 0; j < m; j++) 
  887.         {
  888.           imin[j] = MAXLONG;
  889.           imax[j] = -MAXLONG;
  890.           imean[j] = 0;
  891.           imeansq[j] = 0;
  892.         }
  893.       
  894.       for (i = n, iptr = (int *) vdata->data; i > 0; i--) 
  895.         {
  896.           for (j = 0; j < m; j++, iptr++) 
  897.             {
  898.               ival = *iptr;
  899.               imin[j] = MIN(imin[j], ival);
  900.               imax[j] = MAX(imax[j], ival);
  901.               imean[j] += ival;
  902.               imeansq[j] += ival*ival;
  903.             }
  904.         }
  905.       
  906.       for (j = 0; j < m; j++) 
  907.         {
  908.           PVD (("  [cs] New min/max is %d/%d\n", imin[j], imax[j]));
  909.           
  910.           fmean[j] = ((float) imean[j]) / n;
  911.           fmeansq[j] = ((float) imeansq[j]) / n;
  912.           
  913.           vdata->stats[j].min = (float) imin[j];
  914.           vdata->stats[j].max = (float) imax[j];
  915.           vdata->stats[j].mean = fmean[j];
  916.           vdata->stats[j].mean_sq = fmeansq[j];
  917.           vdata->stats[j].variance = fmeansq[j]-fmean[j]*fmean[j];
  918.         }
  919.       break;
  920.     case PVFLOAT:
  921.       for (j = 0; j < m; j++) 
  922.         {
  923.           fmin[j] = MAXDOUBLE;
  924.           fmax[j] = -MAXDOUBLE;
  925.           fmean[j] = 0.0;
  926.           fmeansq[j] = 0.0;
  927.         }
  928.       
  929.       for (i = n, fptr = (float *) vdata->data; i > 0; i--) 
  930.         {
  931.           for (j = 0; j < m; j++, fptr++) 
  932.             {
  933.               fval = *fptr;
  934.               fmin[j] = MIN(fmin[j], fval);
  935.               fmax[j] = MAX(fmax[j], fval);
  936.               fmean[j] += fval;
  937.               fmeansq[j] += fval*fval;
  938.             }
  939.         }
  940.       
  941.       for (j = 0; j < m; j++) 
  942.         {
  943.           fmean[j] /= n;
  944.           fmeansq[j] /= n;
  945.           vdata->stats[j].min = fmin[j];
  946.           vdata->stats[j].max = fmax[j];
  947.           vdata->stats[j].mean = fmean[j];
  948.           vdata->stats[j].mean_sq = fmeansq[j];
  949.           vdata->stats[j].variance = fmeansq[j]-fmean[j]*fmean[j];
  950.         }
  951.       break;
  952.     default:
  953.       fprintf(stderr, "[calc_data] SYSTEM ERROR: Unsupported data type %d.\n",
  954.               vdata->stats[0].type);
  955.       fflush (stderr);
  956.       break;
  957.     }
  958.   
  959.   /* Set the flag so that we do not do this again. */
  960.   vdata->stats_read = TRUE;
  961.  
  962.   PVD (("[calc_stats] min is %f max is %f\n",
  963.         vdata->stats[0].min, vdata->stats[0].max));
  964.   
  965.   return ST_OKAY;
  966. }
  967.  
  968.  
  969. int combine_stats(state_t *state, stats_t updstat[MAXDATADIMS][MAXVDATAS],
  970.                   stats_t newstat[MAXDATADIMS][MAXVDATAS])
  971. {
  972.   stats_t *upd, *new;
  973.   int i,j;
  974.   
  975.   for (i = 0; i < MAXDATADIMS; i++) 
  976.     {
  977.       for (j = 0; j < MAXVDATAS; j++) 
  978.         {
  979.           upd = &updstat[i][j];
  980.           new = &newstat[i][j];
  981.           assert ((upd != NULL) && (new != NULL));
  982.           upd->type = new->type;
  983.           upd->rec_size = new->rec_size;
  984.           PVD (("[combine_stats] &&&&&&&&& rec_size 1 is %d, 2 is %d\n",
  985.                 new->rec_size, upd->rec_size));
  986.           upd->rec_count = new->rec_count;
  987.           upd->min = MIN(upd->min, new->min);
  988.           upd->max = MAX(upd->max, new->max);
  989.           upd->mean = (upd->mean + new->mean)/2;
  990.           upd->mean_sq = (upd->mean_sq + new->mean_sq)/2;
  991.           upd->variance = upd->mean_sq - (upd->mean * upd->mean);
  992.         }
  993.     }
  994.   
  995.   return ST_OKAY;
  996. }
  997.  
  998.  
  999. /* ------------------------------------------------------------------------ */
  1000. /* ---------------------------- dump functions ---------------------------- */
  1001. /* ------------------------------------------------------------------------ */
  1002.  
  1003. static int dump_data(int i, Vdata_t *data)
  1004. {
  1005.   int j, k;
  1006.   
  1007.   for ( ; data != NULL; data = data->sibling) 
  1008.     {
  1009.       for (k = 0; k < data->stats[0].rec_size; k++) 
  1010.         {
  1011.           for (j=i; j > 0; j--) 
  1012.             printf("  ");
  1013.           if (k == 0) {
  1014.             printf("DATA: %c%-6s",
  1015.                    (data->in_memory)?'*':' ', data->name);
  1016.           }
  1017.           else if (data->in_memory) 
  1018.             {
  1019.               printf("%13s", "");
  1020.             }
  1021.           
  1022.           if (data->in_memory) 
  1023.             {
  1024.               printf(" %02d %c %5d %1d %.2f %.2f %.2f %lx\n",
  1025.                      data->id,
  1026.                      (data->stats[0].type == PVINTEGER)?
  1027.                      'I' : 'F',
  1028.                      data->stats[0].rec_count,
  1029.                      data->stats[0].rec_size,
  1030.                      data->stats[k].min,
  1031.                      data->stats[k].mean,
  1032.                      data->stats[k].max,
  1033.                      (long) data);
  1034.             }
  1035.           else 
  1036.             {
  1037.               printf("\n");
  1038.             }
  1039.         }
  1040.     }
  1041.  
  1042.   return ST_OKAY;
  1043. }
  1044.  
  1045.  
  1046. static int dump_groups(int i, Vgroup_t *group)
  1047. {
  1048.   int j;
  1049.   
  1050.   for (j = i; j > 0; j--) 
  1051.     printf("  ");
  1052.   printf("[dump_groups] GROUP: %s\n", group->name);
  1053.   dump_data(i+1, group->vdatas);
  1054.   for (group = group->groups; group != NULL; group = group->sibling) 
  1055.     dump_groups(i+1, group);
  1056.  
  1057.   return ST_OKAY;
  1058. }
  1059.  
  1060.  
  1061. int dump_files(state_t *state)
  1062. {
  1063.   files_t *file;
  1064.   
  1065.   for (file = state->files; file != NULL; file = file->next) 
  1066.     {
  1067.       printf("[dump_files] FILE: %s\n", file->path);
  1068.       /* Recurse here: */
  1069.       dump_groups(1, file->groups);
  1070.     }
  1071.  
  1072.   return ST_OKAY;
  1073. }
  1074.